﻿#region

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml.Serialization;
using MediaSage.Lib.Configuration;
using MediaSage.Lib.Database;
using MediaSage.Lib.Utilities;

#endregion

namespace MediaSage.Lib.Plugin.FileDataProvider
{
    /// <summary>
    ///     Provides access to other metadata projects files
    ///     Like: MyMovies, dvdid.xml files
    /// </summary>
    public class FileDataProvider : PluginBase
    {
        protected bool scanDVDID = false;
        protected bool scanMyMoviesXML = false;
        protected bool scanSeriesXML = false;

        #region Constructors

        public FileDataProvider(Config Configuration, PluginEntity PE)
            : base(Configuration, PE)
        {
            logger.Log("Initializing FileDataProvider");
            var ciH = new ConfigItemsHelper(config);
            PluginConfigurationItemEntity piCE = ciH.GetCIByNameForPlugin(base.pluginEntity.ID, "ScanDVDID");
            if (piCE.Value.ToUpper().Equals("TRUE"))
            {
                scanDVDID = true;
            }
            piCE = ciH.GetCIByNameForPlugin(base.pluginEntity.ID, "ScanSeriesXML");
            if (piCE.Value.ToUpper().Equals("TRUE"))
            {
                scanSeriesXML = true;
            }
            piCE = ciH.GetCIByNameForPlugin(base.pluginEntity.ID, "ScanMyMoviesXML");
            if (piCE.Value.ToUpper().Equals("TRUE"))
            {
                scanDVDID = true;
            }
            logger.Log(
                String.Format("FileDataProvider Initialized with: ScanDVDID=%s, ScanSeriesXML=%s, ScanMyMoviesXML=%s",
                              scanDVDID.ToString(), scanSeriesXML.ToString(), scanMyMoviesXML.ToString()));
        }

        #endregion Constructors

        #region Methods

        public override bool Run(MediaClass mediaObject)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not applicable for this plugin
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public override IList<PersonEntity> SearchPersonByName(string name)
        {
            throw new NotImplementedException();
        }

        public override string[] About()
        {
            VersionInfo verInfo = GetVersionInfo();

            string[] returnValue =
                {
                    "FileDataProvider v" + verInfo.MajorVersion + "." + verInfo.MinorVersion + "." +
                    verInfo.BuildNumber
                };
            return returnValue;
        }

        public override IList<MediaFileTypesEntity> ExtensionsHandled()
        {
            throw new NotImplementedException();
        }

        public override PluginEntity GetConfiguration()
        {
            throw new NotImplementedException();
        }

        public override MediaClass GetMedia(MediaClass inputMedia, MediaMergeType mergeType)
        {
            logger.Log("Entering FileDataProvider::SearchForMedia(mediaObject)");
            string directory = Path.GetFullPath(inputMedia.Filename);
            if (!Directory.Exists(directory))
            {
                logger.Log(Logger.Levels.WARN, String.Format("Path: %s does not exist", directory));
                logger.Log("Entering FileDataProvider::SearchForMedia(mediaObject), rc==null");
                return null;
            }

            string[] files = Directory.GetFileSystemEntries(directory, "*.xml");
            MediaClass MyMoviesObject = new MediaClass(config);
            MediaClass SeriesObject = new MediaClass(config);
            MediaClass DVDIDObject = new MediaClass(config);
            foreach (string file in files)
            {
                logger.Log(String.Format("Checking if: %s needs processing", file));
                if ((file.ToUpper().Equals("MYMOVIES.XML") || file.ToUpper().Equals("MOVIE.XML")) && scanMyMoviesXML)
                {
                    logger.Log("Scanning MyMovies file");
                    MyMoviesObject = scanMyMovies(file);
                }
                if (file.ToUpper().Equals("SERIES.XML") && scanSeriesXML)
                {
                    logger.Log("Scanning Series.XML file");
                    SeriesObject = scanSeries(file);
                }
                if (file.ToUpper().Contains("DVDID.XML") && scanDVDID)
                {
                    logger.Log("Scanning DVDID.xml file");
                    DVDIDObject = scanDVDIDFile(file);
                }
            }

            // Merge the objects we got in this method together to form one

            MediaClass returnObject = MediaUtil.MergeMediaObjects(config, MyMoviesObject, SeriesObject,
                                                                  MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY);
            MediaUtil.MergeMediaObjects(config, returnObject, DVDIDObject,
                                        MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY);

            // Merge that with what we got from the update

            returnObject = MediaUtil.MergeMediaObjects(config, inputMedia, returnObject, mergeType);

            logger.Log("Exiting FileDataProvider::SearchForMedia(mediaObject)");

            return returnObject;
        }

        public override MediaClass GetMediaByID(object ID)
        {
            throw new NotImplementedException();
        }

        public override MediaClass GetUpdateForMedia(MediaClass inputMedia, MediaMergeType MergeType)
        {
            throw new NotImplementedException();
        }

        public override VersionInfo GetVersionInfo()
        {
            VersionInfo verInfo;
            verInfo.Name = Assembly.GetExecutingAssembly().GetName().Name;
            verInfo.MajorVersion = Assembly.GetExecutingAssembly().GetName().Version.Major;
            verInfo.MinorVersion = Assembly.GetExecutingAssembly().GetName().Version.Minor;
            verInfo.BuildNumber = Assembly.GetExecutingAssembly().GetName().Version.Revision;
            return verInfo;
        }

        public override bool Run()
        {
            throw new NotImplementedException();
        }

        private MediaClass scanDVDIDFile(string filename)
        {
            logger.Log(String.Format("Entering FileDataProvider::scanSeries(%s)", filename));
            MediaClass mcReturn = new MediaClass(config);
            Disc disc = null;
            try
            {
                StreamReader streamReader = new StreamReader(filename);
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(Series));
                disc = (Disc)xmlSerializer.Deserialize(streamReader);
                streamReader.Close();
            }
            catch (Exception e)
            {
                logger.Log(Logger.Levels.WARN,
                           String.Format("Exeception processing file: %s, exception: %s", filename, e));
                logger.Log(String.Format("Exiting FileDataProvider::scanDVDIDFile(%s)", filename));
                return mcReturn;
            }
            if (disc != null)
            {
                mcReturn.Name = disc.Name;
                mcReturn.DVDId = disc.ID;
            }
            return (mcReturn);
        }

        private MediaClass scanSeries(string filename)
        {
            logger.Log(String.Format("Entering FileDataProvider::scanSeries(%s)", filename));
            MediaClass mcReturn = new MediaClass(config);
            Series series = null;
            try
            {
                StreamReader streamReader = new StreamReader(filename);
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(Series));
                series = (Series)xmlSerializer.Deserialize(streamReader);
                streamReader.Close();
            }
            catch (Exception e)
            {
                logger.Log(Logger.Levels.WARN,
                           String.Format("Exeception processing file: %s, exception: %s", filename, e));
                logger.Log(String.Format("Exiting FileDataProvider::scanSeries(%s)", filename));
                return mcReturn;
            }

            if (series != null)
            {
                string[] tmpStr = series.Actors.Split('|');
                foreach (string actor in tmpStr)
                {
                    if (!String.IsNullOrWhiteSpace(actor))
                    {
                        PersonEntity pe = new PersonEntity();
                        pe.Name = actor;
                        mcReturn.Cast.Add(pe);
                    }
                }
                mcReturn.Name = series.SeriesName;
                tmpStr = series.Genre.Split('|');
                foreach (string genre in tmpStr)
                {
                    if (!String.IsNullOrWhiteSpace(genre))
                    {
                        mcReturn.Genre.Add(genre);
                    }
                }
                if (!String.IsNullOrWhiteSpace(series.IMDB_ID))
                {
                    mcReturn.IMDBID = series.IMDB_ID;
                }
                else
                {
                    if (!String.IsNullOrWhiteSpace(series.IMDbId))
                    {
                        mcReturn.IMDBID = series.IMDbId;
                    }
                }
                mcReturn.NetworkAffiliation = series.Network;
                mcReturn.Overview = series.Overview;
                mcReturn.Rating = (double)series.Rating;
                mcReturn.IsTVSeries = true;
            }

            logger.Log(String.Format("Exiting FileDataProvider::scanSeries(%s)", filename));
            return (mcReturn);
        }

        private MediaClass scanMyMovies(string filename)
        {
            logger.Log(String.Format("Entering FileDataProvider::scanMyMovies(%s)", filename));
            MediaClass mcReturn = new MediaClass(config);

            Title title = null;
            try
            {
                StreamReader streamReader = new StreamReader(filename);
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(Title));
                title = (Title)xmlSerializer.Deserialize(streamReader);
                streamReader.Close();
            }
            catch (Exception e)
            {
                logger.Log(Logger.Levels.WARN,
                           String.Format("Exeception processing file: %s, exception: %s", filename, e));
                logger.Log(String.Format("Exiting FileDataProvider::scanMyMovies(%s)", filename));
                return mcReturn;
            }

            if (title != null)
            {
                // We need to incorporate all the data in the file into our mediaclass
                mcReturn.Name = title.LocalTitle;
                mcReturn.VideoAspect = title.AspectRatio;
                mcReturn.Budget = title.Budget.ToString();
                foreach (string genre in title.Genres)
                {
                    mcReturn.Genre.Add(genre);
                }
                mcReturn.IMDBID = title.IMDbId;
                mcReturn.TmdbID = title.TMDbId;
                if (title.Subtitles.NotPresent.ToUpper().Equals("TRUE"))
                {
                    mcReturn.IsSubtitled = true;
                }
                else
                {
                    mcReturn.IsSubtitled = false;
                }
                foreach (string studio in title.Studios)
                {
                    mcReturn.Studios.Add(studio);
                }
                foreach (TitlePerson person in title.Persons)
                {
                    PersonEntity pe = new PersonEntity();
                    pe.Name = person.Name;
                    FilmographyEntity fe = new FilmographyEntity();
                    fe.Character = person.Role;
                    fe.Job = person.Type;
                }
                mcReturn.Countries.Add(title.Country);
                mcReturn.Description = title.Description;
                mcReturn.Languages.Add(title.Language);
                mcReturn.MPAARating = title.MPAARating;
                DateTime temp;
                DateTime.TryParse(title.ReleaseDate, out temp);
                mcReturn.Released = temp;
                mcReturn.Subtitle = title.TagLine.ToString();
            }
            logger.Log(String.Format("Exiting FileDataProvider::scanMyMovies(%s)", filename));
            return mcReturn;
        }

        public override List<MediaSearchReturn> SearchForMedia(MediaClass mediaObject)
        {
            throw new NotImplementedException();
        }

        public override List<MediaSearchReturn> SearchForMedia(MediaClass mediaObject, int maxReturns)
        {
            throw new NotImplementedException();
        }

        public override List<MediaSearchReturn> SearchForMediaByName(string name)
        {
            throw new NotImplementedException();
        }

        public override List<MediaSearchReturn> SearchForMediaByName(string name, int maxReturns)
        {
            throw new NotImplementedException();
        }

        public override List<MediaSearchReturn> SearchForMediaByNameAndYear(string name, int year)
        {
            throw new NotImplementedException();
        }

        public override List<MediaSearchReturn> SearchForMediaByNameAndYear(string name, int year, int maxReturns)
        {
            throw new NotImplementedException();
        }

        public override void SetDefaultConfig()
        {
            // Config Variables are:
            // Name - ScanDVDID
            // Type - bool
            // Provider ID - This guys ID
            // Description - Scan and import DVDID files
            // Value - true

            // Name - ScanSeriesXML
            // Type - bool
            // Provider ID - This guys ID
            // Description - Scan and import Series.xml files
            // Value - true

            // Name - ScanMyMovies.xml
            // Type - bool
            // Provider ID - This guys ID
            // Description - Scan and import mymovies.xml files
            // Value - true

            logger.Log("Entering FileDataProvider.SetDefaultConfig()");
            VersionInfo vi = GetVersionInfo();
            pluginEntity.BuildNumber = vi.BuildNumber;
            pluginEntity.MajorVersion = vi.MajorVersion;
            pluginEntity.MinorVersion = vi.MinorVersion;
            pluginEntity.Name = vi.Name;
            pluginEntity.PluginType = PluginType.file;
            pluginEntity.SaveOrUpdate();

            var ciH = new ConfigItemsHelper(config);

            ciH.CreateCIEntry(pluginEntity.ID, "ScanDVDID", EValueType.BOOL, "TRUE",
                              "Scan and import DVDID.xml files");
            logger.Log(
                String.Format("Set TMDBProvider Variable - Name: ScanDVDID, type: bool, value: TRUE, ProviderID: {0}",
                              base.pluginEntity.ID));

            ciH.CreateCIEntry(pluginEntity.ID, "ScanSeriesXML", EValueType.BOOL, "TRUE",
                              "Scan and import series.xml files");
            logger.Log(
                String.Format(
                    "Set TMDBProvider Variable - Name: ScanSeriesXML, type: bool, value: TRUE, ProviderID: {0}",
                    base.pluginEntity.ID));

            ciH.CreateCIEntry(pluginEntity.ID, "ScanMyMoviesXML", EValueType.BOOL, "TRUE",
                              "Scan and import DVDID.xml files");
            logger.Log(
                String.Format(
                    "Set TMDBProvider Variable - Name: ScanMyMoviesXML, type: bool, value: TRUE, ProviderID: {0}",
                    base.pluginEntity.ID));
            var tmp = new MediaFileTypesEntity();
            tmp.Description = "XML Data File";
            tmp.Extension = "xml";
            pluginEntity.ExtensionsHandled.Add(tmp);
            pluginEntity.SaveOrUpdate();
            logger.Log("Exiting FileDataProvider.SetDefaultConfig()");
        }

        #endregion Methods
    }
}